﻿using System;
using System.Configuration;
using System.Diagnostics;

namespace Fadd.Logging
{
    /// <summary>
    /// Used to access loggers.
    /// </summary>
    public class LogManager
    {
        private static ILogProvider _provider;
        private static Type _providerAssigner;

        /// <summary>
        /// Logger that is logging to nothing.
        /// </summary>
        public static readonly NullLogger NullLogger = new NullLogger();

        /// <summary>
        /// Initializes the <see cref="LogManager"/> class.
        /// </summary>
        static LogManager()
        {

        }

        /// <summary>
        /// Gets the logger.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns><c>null</c> will never be returned, you can always safely use the
        /// returned logger. </returns>
        public static ILogger GetLogger(string name)
        {
            return _provider == null ? NullLogger : _provider.GetLogger(name);
        }

        /// <summary>
        /// Get logger for the current class.
        /// </summary>
        /// <returns><c>null</c> will never be returned, you can always safely use the
        /// returned logger. </returns>
        public static ILogger GetCurrentClassLogger()
        {
            return _provider == null ? NullLogger : _provider.GetCurrentClassLogger();
        }

        /// <summary>
        /// Set the provider used to get loggers.
        /// </summary>
        /// <param name="provider"></param>
        /// <exception cref="InvalidOperationException">A log provider have already been specified.</exception>
        public static void SetProvider(ILogProvider provider)
        {
            if (_provider != null)
                throw new InvalidOperationException("A LogProvider have already been specified by " +
                                                    _providerAssigner.FullName);

            _providerAssigner = new StackFrame(1).GetMethod().ReflectedType;
            _provider = provider;
        }

        /// <summary>
        /// Used to trigger the exception thrown event.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="exception"></param>
        internal static void TriggerEvent(object source, Exception exception)
        {
            ExceptionThrown(source, new ExceptionEventArgs {Exception = exception});
        }

        /// <summary>
        /// Invoked when a unhandled exception is thrown by the logging framework.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Exceptions can for instance be if the file target cannot create a log file
        /// or a log directory.
        /// </para>
        /// </remarks>
        public static event EventHandler<ExceptionEventArgs> ExceptionThrown = delegate{};
    }
}
